package com.macro.mall.portal.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.portal.dao.PayDepositMapper;
import com.macro.mall.portal.domain.Partner;
import com.macro.mall.portal.domain.PayDeposit;
import com.macro.mall.portal.domain.RefundDeposit;
import com.macro.mall.portal.domain.User;
import com.macro.mall.portal.domain.vo.PayVo;
import com.macro.mall.portal.domain.vo.WxMsgVo;
import com.macro.mall.portal.service.IPartnerService;
import com.macro.mall.portal.service.IUserService;
import com.macro.mall.portal.service.PayDepositService;
import com.macro.mall.portal.service.RefundDepositService;
import com.macro.mall.portal.util.ConfigConstant;
import com.macro.mall.portal.util.IpUtils;
import com.macro.mall.portal.util.MyCodeUtil;
import com.macro.mall.portal.util.WxMsgPush;
import com.macro.mall.portal.wxpay.domain.vo.CreateOrderVO;
import com.macro.mall.portal.wxpay.helper.MyWeChatPayUtil;
import com.macro.mall.portal.wxpay.helper.WxpayHelper;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;

/**
 * 支付定金表 服务实现类
 *
 * @author db
 * @since 2021-09-07
 */
@Slf4j
@Service
public class PayDepositServiceImpl extends ServiceImpl<PayDepositMapper, PayDeposit> implements PayDepositService {

    @Autowired
    private WxpayHelper wxpayHelper;

    @Autowired
    private RefundDepositService refundDepositService;

    @Autowired
    private MyWeChatPayUtil myWeChatPayUtil;

    @Autowired
    private IUserService userService;

    @Autowired
    private WxMsgPush wxMsgPush;

    @Autowired
    private IPartnerService partnerService;

    @Override
    public CommonResult pay(PayDeposit payDeposit, HttpServletRequest request) {
        if (StringUtils.isEmpty(payDeposit.getPhone()) || StringUtils.isEmpty(payDeposit.getPayOpenId())) {
            return CommonResult.failed("手机号或付款人openid不能为空");
        }
        if (StringUtils.isEmpty(payDeposit.getMoney())) {
            return CommonResult.failed("金额不能为空");
        }
        //转换微信支付单位分
        BigDecimal money = payDeposit.getMoney().multiply(new BigDecimal(100));
        BigDecimal minute = money.setScale(0, BigDecimal.ROUND_HALF_UP);

        String orderNumber = MyCodeUtil.getOrderNumber23();
        String ipAddress = IpUtils.getClientIPAddress(request);
        String notifyUrl = "https://mane.szdrkg.com/payDeposit/callBack";
//        String notifyUrl = "http://hiznrp.natappfree.cc/payDeposit/callBack";
        //todo 回调需要参数
        PayVo payVo = new PayVo();
        payVo.setPhone(payVo.getPhone());
        Object obj = JSONArray.toJSON(payVo);


        //调去微信支付
        CreateOrderVO orderVO = CreateOrderVO
                .builder()
                .attachJson(obj.toString())
                .ip(ipAddress)
                .body("金池时贷-定金")
                .orderNumber(orderNumber)
                .totalFee(minute.intValue())
                .h5Url(payDeposit.getH5Url())
                .notifyUrl(notifyUrl)
                .openId(payDeposit.getPayOpenId())
                .urlName("定金")
                .build();
        String sign = wxpayHelper.unifiedOrderHelper_H5(orderVO).toString();
        System.out.println(sign);
        //创建预支付订单
        payDeposit.setOrderId(orderNumber);
        payDeposit.setPayName("微信JSAPI支付");
        payDeposit.setStatus(1);

        this.save(payDeposit);

        HashMap<String, Object> map = new HashMap<>();
        map.put("sign", sign);
        map.put("orderNumber", orderNumber);
        return CommonResult.success(map);
    }

    @Override
    public CommonResult queryOrderStatus(PayVo payVo) {
        if (StringUtils.isEmpty(payVo.getOrderNumber())) {
            return CommonResult.failed("订单号不能为空");
        }
        QueryWrapper<PayDeposit> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", payVo.getOrderNumber());
        PayDeposit one = this.getOne(wrapper);
        if (one.getStatus() == 2) {
            return CommonResult.success(null, "支付成功");
        } else if (one.getStatus() == 3) {
            return CommonResult.failed("支付失败");
        }
        return CommonResult.success(201, null, "回调中");
    }

    @Override
    public CommonResult check(PayVo payVo) {
        if (StringUtils.isEmpty(payVo.getPhone()) || StringUtils.isEmpty(payVo.getPayOpenId())) {
            return CommonResult.failed("手机号或openid不能为空");
        }
        QueryWrapper<PayDeposit> wrapper = new QueryWrapper<>();
        wrapper.eq("pay_open_id", payVo.getPayOpenId());
        wrapper.eq("phone", payVo.getPhone());
        wrapper.eq("status", 2);
        List<PayDeposit> depositList = this.list(wrapper);
        if (StringUtils.isEmpty(depositList) || depositList.size() == 0) {
            return CommonResult.failed("未存在相关已成功支付的定金信息！");
        }
        return CommonResult.success(depositList);
    }


    @Override
    public void add(RefundDeposit refundDeposit) {
        QueryWrapper<PayDeposit> wrapper = new QueryWrapper<>();
        wrapper.eq("order_id", refundDeposit.getOutTradeNo());
        PayDeposit deposit = this.getOne(wrapper);
        refundDeposit.setRefundFee(deposit.getMoney());
        refundDeposit.setOutRefundNo(MyCodeUtil.getOrderNumber23());
        refundDeposit.setRefundStatus(1);
        refundDeposit.setCheckStatus(1);
        refundDepositService.save(refundDeposit);
    }

    @Override
    public Document callBack(String req) {
        // 记录回调日志

        // 响应预设
        Document resXml = DocumentHelper.createDocument();
        Element resRoot = resXml.addElement("xml");
        resRoot.addElement("return_code").addCDATA("SUCCESS");
        resRoot.addElement("return_msg").addCDATA("OK");

        String orderNumber = null;

        try {
            Document reqXml = DocumentHelper.parseText(req);// 请求参数
            Element reqRoot = reqXml.getRootElement();

            String returnCode = reqRoot.element("return_code").getText();// 通信标识，接收正确参数
            if ("SUCCESS".equals(returnCode)) {
                // 校验签名
                boolean checkSign = myWeChatPayUtil.checkSign(reqXml);
                if (checkSign) {
                    // 业务结果，"SUCCESS"支付成功，"FAIL"支付失败
                    String resultCode = reqRoot.element("result_code").getText();
                    // 回调额外数据
                    String attachStr = reqRoot.element("attach").getText();
                    // 商户订单号
                    orderNumber = reqRoot.element("out_trade_no").getText();
//                    synchronized (IpUtils.LOCK_POOL.intern(orderNumber)) {

                    // 订单金额，单位：分
                    String totalFee = reqRoot.element("total_fee").getText();
                    // 订单金额，单位：元
                    BigDecimal price = new BigDecimal(totalFee).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_HALF_UP);
                    // 支付完成时间，格式为：yyyyMMddHHmmss
                    String payTime = reqRoot.element("time_end").getText();

                    JSONObject attachJson = new JSONObject(attachStr);
//                    ProudPayEnum proudPay = ProudPayEnum.toType(attachJson.optString("productPayType"));

                    try {
                        //  业务
                        if ("SUCCESS".equals(resultCode)) {
                            String code = query(orderNumber);
                            if (!code.equalsIgnoreCase("SUCCESS")) {
                                throw new Exception("支付异常");
                            }
                        } else {
                            log.info("进入微信回调：{}，orderNumber：{}", "失败", orderNumber);
                        }
                    } catch (Exception e) {
                        resRoot.remove(resRoot.element("return_code"));
                        resRoot.remove(resRoot.element("return_msg"));

                        resRoot.addElement("return_code").addCDATA("FAIL");
                        resRoot.addElement("return_msg").addCDATA(e.getMessage());
                    }
//                    }
                    //todo 同步锁
                } else {
                    resRoot.remove(resRoot.element("return_code"));
                    resRoot.remove(resRoot.element("return_msg"));

                    resRoot.addElement("return_code").addCDATA("FAIL");
                    resRoot.addElement("return_msg").addCDATA("签名失败");
                }

            } else {
                resRoot.remove(resRoot.element("return_code"));
                resRoot.remove(resRoot.element("return_msg"));

                resRoot.addElement("return_code").addCDATA("FAIL");
                resRoot.addElement("return_msg").addCDATA("通信标识：return_code=FAIL");
            }

        } catch (DocumentException e) {
            resRoot.remove(resRoot.element("return_code"));
            resRoot.remove(resRoot.element("return_msg"));

            resRoot.addElement("return_code").addCDATA("FAIL");
            resRoot.addElement("return_msg").addCDATA("参数格式校验错误：" + e.getMessage());
        }

        log.info("微信支付回调响应：{}，订单号：{}", resXml.getRootElement().asXML(), orderNumber);
        return resXml;
    }

    public String query(String orderNumber) {
        synchronized (IpUtils.LOCK_POOL.intern(orderNumber)) {
            QueryWrapper<PayDeposit> wrapper = new QueryWrapper<>();
            wrapper.eq("order_id", orderNumber);
            PayDeposit one = this.getOne(wrapper);
            if (one == null) {
                return "error";
            }
            if (one.getStatus() == 2) {
                return "SUCCESS";
            }
            PayDeposit payDeposit = PayDeposit.builder()
                    .status(2)
                    .id(one.getId())
                    .build();
            boolean b = this.updateById(payDeposit);
            partner(one);
            if (b == false) {
                return "error";
            }
            return "SUCCESS";
        }
    }

    @Override
    public void partner(PayDeposit one) {
        log.info("------------------------进入合伙人");
        QueryWrapper<User> subWrapper = new QueryWrapper<>();
        subWrapper.eq("account", one.getRemark());
        User sub = userService.getOne(subWrapper);

        Integer superId = 3;
        String openId = ConfigConstant.D_OPEN;
        if (sub != null) {
            superId = sub.getId();
            openId = sub.getOpenId();
        }
        //添加hhr
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("open_id", one.getPayOpenId());
        User user = userService.getOne(userWrapper);

        Integer subs = 7;

        if (user != null && user.getSuperId() == 0) {
            log.info("------------------------进入合伙人+" + "user != null && user.getSuperId() == 0");
            user.setAccount(one.getAccount());
            user.setPhone(one.getPhone());
            user.setIdent(ConfigConstant.YWY);
            user.setSuperId(superId);
            userService.updateById(user);
        } else if (user != null && user.getSuperId() != 0) {
            log.info("------------------------进入合伙人+" + "user != null && user.getSuperId() != 0");
            subs = 777;
        } else if (user == null) {
            log.info("------------------------进入合伙人+" + "user = null ");
            user.setOpenId(one.getOpenId());
            user.setAccount(one.getAccount());
            user.setPhone(one.getPhone());
            user.setIdent(ConfigConstant.YWY);
            user.setSuperId(superId);
            userService.save(user);
        }

        log.info("------------------------推送 " + sub.getOpenId());
        String url = ConfigConstant.HHR_URL;
        LocalDateTime time = LocalDateTime.now();

        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        String now = dtf2.format(time);
        WxMsgVo msgVo = WxMsgVo.builder()
                .first("您好！客户已支付成功")
                .keyword1(one.getAccount() + "｜" + one.getPhone())
                .keyword2(now)
                .openId(sub.getOpenId())
//                .url(url)
                .remark("已支付成功、客户归属为下级合伙人" + "-" + "等级为业务员")
                .build();
        //todo 通知
        log.info("------------------------推送 " + sub.getOpenId());
        if (subs == 777) {
            msgVo = WxMsgVo.builder()
                    .first("您好！客户已支付成功")
                    .keyword1(one.getAccount() + "｜" + one.getPhone())
                    .keyword2(now)
                    .openId(sub.getOpenId())
//                    .url(url)
                    .remark("已支付成功、客户已存在上级无法绑定")
                    .build();

        }
        log.info("------------------------推送 " + sub.getOpenId());
        Partner partner = Partner.builder()
                .openId(openId)
                .name(one.getAccount())
                .shareName(one.getRemark())
                .phone(one.getPhone())
                .partnerStatus(2)
                .build();
        partnerService.save(partner);
        wxMsgPush.SendWxMsg(msgVo);

    }


}
